package com.seven.annotation;

import com.seven.commons.AbstractSevenException;
import com.seven.commons.AnnotationException;
import com.seven.commons.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;


@Aspect
@Component
@Order(4)
public class SevenApmComponent extends BaseComponent {

    private static  final Logger LOGGER = LoggerFactory.getLogger(SevenApmComponent.class);

    private static final char FLAG_CHAR =',';
    /**
     * 检测注解的标志
     * 表示class和method的方法上面执行:value = "@within(userAccessAnnotation) || @annotation(userAccessAnnotation)"
     * 表示只能在method上面执行:private final String  annotation= "@annotation(com.ypzdw.annotation.SevenApm)";
     */

    private final String  annotation= "@within(com.seven.annotation.SevenApm) || @annotation(com.seven.annotation.SevenApm)";

    @Pointcut(annotation)
    public void controllerPoint(){}

    @Before("controllerPoint()")
    public void before(){}
    @After("controllerPoint()")
    public void after(){}

    @Around("controllerPoint()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        //拼接参数的值和类型
        MethodSignature joinPointObject = (MethodSignature) joinPoint.getSignature();
        Method method = joinPointObject.getMethod();
        //方法上面有注解，忽略class上面的值
        boolean flag = method.isAnnotationPresent(SevenApm.class);
        boolean apm = false;
        boolean response=false;
        if (flag){
            SevenApm annotation = method.getAnnotation(SevenApm.class);
            apm = annotation.apm();
            boolean params = annotation.params();
            response = annotation.response();

            String info = annotation.info();
            //进行方法级别的业务逻辑的处理
            if (LOGGER.isDebugEnabled()){
                LOGGER.debug("method: apm {}: params {} : response {}: info {}",apm,params,response,info);
            }
            showParams(params,joinPoint,method,info);

        }else{
            SevenApm classAnnotation = AnnotationUtils.findAnnotation(joinPointObject.getMethod().getDeclaringClass(), SevenApm.class);
            apm = classAnnotation.apm();
            boolean params = classAnnotation.params();
            response = classAnnotation.response();
            String info = classAnnotation.info();
            //进行方法级别的业务逻辑的处理
            if (LOGGER.isDebugEnabled()){
                LOGGER.debug("class: apm {}: params {} : response {}: info {}",apm,params,response,info);
            }
            showParams(params,joinPoint,method,info);
        }
        Object obj = null;
        try {
            long startTime =  System.currentTimeMillis();
            obj = joinPoint.proceed(joinPoint.getArgs());
            if (apm){
                LOGGER.info("性能时间统计:({})ms",(System.currentTimeMillis()-startTime));
            }
            if (response){
                final String s = JsonUtils.objectToJson(obj);
                LOGGER.info("结果返回值是:{}",s);
            }
        }
        catch (AbstractSevenException e){
            throw new AnnotationException(e.getCode(),e.getMessage());
        }
        catch (Throwable e) {
            throwException(e);
        }
        return obj;

    }
    /**
     * 进行是否显示进入的参数
     * @param show
     * @param joinPoint
     */
    private void showParams(boolean show,ProceedingJoinPoint joinPoint,Method method,String info){
        final Object[] args = joinPoint.getArgs();
        //进行日志信息的打印info
        LOGGER.info(StringUtils.isEmpty(info)?"":info);
        if (show){
            if (!Objects.isNull(args)){
                //拼接参数
                StringBuilder builder = new StringBuilder();
                final String className = joinPoint.getTarget().getClass().getName();
                final String methodName = method.getName();
                builder.append(className+"."+methodName);
                builder.append("(");
                for (Object obj:args) {
                    if (LOGGER.isDebugEnabled()&&(!Objects.isNull(obj))){
                        LOGGER.debug("参数类型:"+obj.getClass().getTypeName()+"===>参数值:"+obj.toString());
                    }
                    if (!Objects.isNull(obj)){
                        builder.append(" "+obj.getClass().getTypeName()+" "+obj.toString()+",");
                    }
                }
                final char c = builder.charAt(builder.length() - 1);
                if (c==FLAG_CHAR){
                    builder.deleteCharAt(builder.length() - 1);
                }
                builder.append(")");
                //进行打印请求的参数
                LOGGER.info("request params is :==>[{}]",builder.toString());

            }

        }
    }

}
